package cn.xzqwjw.taskmanager.security;

import cn.xzqwjw.taskmanager.common.customEnum.ResponseCodeEnum;
import cn.xzqwjw.taskmanager.domain.pojo.LogLogin;
import cn.xzqwjw.taskmanager.domain.pojo.SysAdmin;
import cn.xzqwjw.taskmanager.service.LogLoginService;
import cn.xzqwjw.taskmanager.service.SysAdminService;
import cn.xzqwjw.taskmanager.utils.CryptoUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 这是验证登录的Provider
 *
 * @author rush
 */
@Component
public class LoginAuthAdminProvider implements AuthenticationProvider {

  private final SysAdminService adminService;
  private final LogLoginService logLoginService;

  @Autowired
  public LoginAuthAdminProvider(SysAdminService adminService,
                                LogLoginService logLoginService) {
    this.adminService = adminService;
    this.logLoginService = logLoginService;
  }

  /**
   * providers列表里遍历所有的provider，拿token来验证，
   * 如果不是我这个方法要用到的token，就不执行下面的authentication方法
   */
  @Override
  public boolean supports(Class<?> authentication) {
    return TokenAdmin.class.isAssignableFrom(authentication);
  }

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    TokenAdmin token = (TokenAdmin) authentication;
    if (Objects.isNull(token.getPrincipal())) {
      throw new UsernameNotFoundException("用户名不能为空！");
    }
    String username = token.getPrincipal().toString();
    if (Objects.isNull(token.getCredentials())) {
      throw new BadCredentialsException("密码不能为空！");
    }
    String password = token.getCredentials().toString();
    String ipInner = token.getIpInner();
    String ipOuter = token.getIpOuter();
    // 从数据库中根据用户名得到用户
    SysAdmin admin = (SysAdmin) adminService.loadUserByUsername(username);
    // 在serviceImpl里已经抛出了没找到管理员的异常，这里就不需要再抛出此异常
    // 执行到这里，说明找到了有此用户名的管理员，下面进行密码比对
    PasswordEncoder passwordEncoder = CryptoUtil.initEncoder();
    if (!passwordEncoder.matches(password, admin.getPassword())) {
      throw new BadCredentialsException(ResponseCodeEnum.BAD_PASSWORD.getMessage());
    }
    if (!admin.isAccountNonLocked()) {
      throw new LockedException(ResponseCodeEnum.ACCOUNT_LOCKED.getMessage());
    } else if (!admin.isEnabled()) {
      throw new DisabledException(ResponseCodeEnum.ACCOUNT_DISABLED.getMessage());
    } else if (!admin.isAccountNonExpired()) {
      throw new AccountExpiredException(ResponseCodeEnum.ACCOUNT_EXPIRED.getMessage());
    }
    // 执行到这里说明验证成功
    // 更新管理员最后登录时间
    adminService.patchLastLoginTime(admin.getId());
    // 添加一条管理员登录的记录
    LogLogin logLogin = new LogLogin();
    logLogin.setIdAdmin(admin.getId());
    logLogin.setDtLogin(LocalDateTime.now());
    logLogin.setIpInner(ipInner);
    logLogin.setIpOuter(ipOuter);
    logLoginService.save(logLogin);
    // 返回 token 给 provider
    return new UsernamePasswordAuthenticationToken(admin, password, admin.getAuthorities());
  }

}
